package org.steven.crm.app.api;

import com.alibaba.fastjson.JSON;
import com.steven.common.errors.StandardErrors;
import com.steven.xdb.session.DBSession;
import com.steven.xdb.session.DBSessionHolder;
import com.steven.xweb.web.AbstractEntry;
import com.steven.xweb.web.AbstractProcessor;
import com.steven.xweb.web.DataHandler;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.steven.crm.core.Constants;
import org.steven.crm.core.auth.AuthHandler;
import org.steven.crm.core.auth.UserSession;
import org.steven.crm.core.auth.WechatUserAuthHandler;
import org.steven.crm.core.data.ExtViewContext;
import org.steven.crm.core.exception.BusinessErrors;
import org.steven.crm.core.exception.ServiceException;
import org.steven.crm.core.service.accesstoken.AccessTokenService;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class AppEntry extends AbstractEntry {
	private static Logger logger = Logger.getLogger(AbstractEntry.class);

	private static AccessTokenService accessTokenService = new AccessTokenService();

	@Override
	public void checkPriority(String moduleName, String actionName, HttpServletRequest request) throws Exception {
		DataHandler dataHandler = (DataHandler) request.getAttribute("DataHandler");
		boolean needToken = true;
		if (("user".equals(moduleName) || "weixinUser".equals(moduleName))
				&& (actionName.equals("login") || actionName.equals("bind"))) {
			needToken = false;
		}

		if ("systemConfig".equals(moduleName)) {
			needToken = false;
		}


		String token = dataHandler.getStringData("s_token");
		if (needToken) {
			if (StringUtils.isEmpty(token)) {
				throw  new ServiceException(BusinessErrors.AUTH_USER_CODE_WRONG);
			}
			Map<String, String> accessToken = accessTokenService.validate(token);
			Map<String, String> user = getAuthHandler(accessToken).validate(token);

			UserSession.set(user);
		} else if (StringUtils.isNotEmpty(token)) {
			try {
				Map<String, String> accessToken = accessTokenService.validate(token);
				Map<String, String> user = getAuthHandler(accessToken).validate(token);

				UserSession.set(user);
			} catch (Exception e) {
			}
		}
	}

	private AuthHandler getAuthHandler(Map<String, String> accessToken) {
		String clientId = accessToken.get("clientId");
		if (clientId.equals(Constants.CLIENT.WECHAT_APP)) {
			return new WechatUserAuthHandler();
		} else {
			throw new ServiceException(BusinessErrors.AUTH_WRONG.getCode(), "找不到对应的授权客户端");
		}
	}

	@Override
	public String getPriorityErorrPage() {
		return null;
	}

	@Override
	public void afterDoAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			DBSession.commit(DBSessionHolder.get());
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public void doFinally(AbstractProcessor processor) {
		super.doFinally(processor);
		DBSession.close(DBSessionHolder.get());
		DBSessionHolder.destroy();
		UserSession.destroy();
		ExtViewContext.destroy();
	}

	@Override
	public void whenException(Throwable e, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		DBSession.rollback(DBSessionHolder.get());

		if (e instanceof  ServiceException) {
			ServiceException serviceException = (ServiceException) e;
			DBSession.rollback(DBSessionHolder.get());
			logger.error("Service error", e);
			outputException(response, serviceException.getCode(), e.getMessage());
		} else {
			DBSession.rollback(DBSessionHolder.get());
			logger.error("error", e);
			outputException(response, StandardErrors.UNKNOWN.getCode(), StandardErrors.UNKNOWN.getMessage());
		}
	}

	private void outputException(HttpServletResponse response, String status, String message) throws IOException {
		Map<String, Object> data = new HashMap<>();
		data.put("status", status);
		data.put("message", message);
		response.setContentType("application/json");
		response.getOutputStream().write(JSON.toJSONString(data).getBytes("UTF-8"));
	}

	@Override
	public void entryInit() {
		try {
			Application.getInstance().init();
		} catch (Exception e) {
			throw new RuntimeException("entry init error", e);
		}

		LocalDataCache.getInstance().loadData();
	}
	
	@Override
	public void entryDestroy() {
		DBSession.close(DBSessionHolder.get());
		DBSessionHolder.destroy();
		try {
		} catch (Exception e) {
		}
	}
}
